////////////////////////////////////////////////////////////////////////////////
// Copyright 2010 Michael Schmalle - Teoti Graphix, LLC
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0 
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and 
// limitations under the License
// 
// Author: Michael Schmalle, Principal Architect
// mschmalle at teotigraphix dot com
////////////////////////////////////////////////////////////////////////////////

package org.teotigraphix.swizplugin.bundles
{

import org.swizframework.core.ISwiz;
import org.swizframework.utils.logging.SwizLogger;
import org.teotigraphix.swizplugin.api.IExecutableRequest;
import org.teotigraphix.swizplugin.events.BundleEvent;
import org.teotigraphix.swizplugin.services.IBundleService;

/**
 * The <strong>Bundle</strong> is the default implementation 
 * of <code>IBundle</code>.
 * 
 * @author Michael Schmalle
 * @copyright Teoti Graphix, LLC
 * @productversion 1.0
 */
public class Bundle implements IBundle
{	
	//--------------------------------------------------------------------------
	//
	//  Protected :: Properties
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @private
	 */
	protected var logger:SwizLogger = SwizLogger.getLogger(this);
	
	//--------------------------------------------------------------------------
	//
	//  IBundle API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  bundleID
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _bundleID:int = -1;
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#bundleID
	 */
	public function get bundleID():int
	{
		return _bundleID;
	}
	
	/**
	 * @private
	 */	
	public function set bundleID(value:int):void
	{
		_bundleID = value;
	}
	
	//----------------------------------
	//  symbolicName
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#symbolicName
	 */
	public function get symbolicName():String
	{
		return _bundleData.symbolicName;
	}
	
	//----------------------------------
	//  state
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _state:int = BundleState.UNINSTALLED;
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#state
	 */
	public function get state():int
	{
		return _state;
	}
	
	/**
	 * @private
	 */	
	public function set state(value:int):void
	{
		_state = value;
	}
	
	//----------------------------------
	//  context
	//----------------------------------
	
	/**
	 * @private
	 */
	protected var _context:IBundleContext;
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#context
	 */
	public function get context():IBundleContext
	{
		return _context;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Protected :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  bundleData
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _bundleData:BundleData;
	
	/**
	 * @private
	 */
	protected function get bundleData():BundleData
	{
		return _bundleData;
	}
	
	//----------------------------------
	//  bundleService
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _bundleService:IBundleService;
	
	/**
	 * @private
	 */
	protected function get bundleService():IBundleService
	{
		return _bundleService;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @private
	 */
	public function Bundle(bundleData:BundleData, bundleService:IBundleService)
	{
		_bundleData = bundleData;
		_bundleService = bundleService;
		
		_state = BundleState.INSTALLED;
		
		_bundleData.bundle = this;
	}
	
	//--------------------------------------------------------------------------
	//
	//  IBundle API :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#loadClass()
	 */
	public function loadClass(className:String):IExecutableRequest
	{
		return _bundleService.loadClass(this, className);
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#getDefinition()
	 */
	public function getDefinition(className:String):Class
	{
		var clazz:Class;
		
		var context:ISwizContext = context as ISwizContext;
		
		if (context && context.hasDefinition(className))
		{
			clazz = context.getDefinition(className) as Class;
		} 
		else 
		{
			throw new BundleError("Bundle::getDefinition(" + className + ")");
		}
		
		return clazz;
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.bundles.IBundle#hasDefinition()
	 */
	public function hasDefinition(className:String):Boolean
	{
		var context:ISwizContext = context as ISwizContext;
		if (context)
			return context.hasDefinition(className);
		return false;
	}
	
	/**
	 * @private
	 */
	public function load(options:int):void
	{
		loadContext(options);
	}
	
	/**
	 * @private
	 */
	public function start(options:int):void
	{
		startupContext(options);
	}
	
	/**
	 * @private
	 */
	public function loadBundleActivator():IBundleActivator
	{
		var type:Class;
		// load Bundle's BundleActivator if it has one
		var activator:String = _bundleData.activator;
		
		if (!activator)
		{
			// try the class
			type = _bundleData.activatorClass;
		}
		
		if (!activator && !type)
			return null;
		
		var instance:IBundleActivator;
		
		try {
			if (!type)
				type = getDefinition(activator);
			
			instance = new type();
		}
		catch (e:BundleError) {
			logger.error("Activator failed to load [{0}], {1}", activator, e.message);
		}
		catch (e2:TypeError) {
			// TypeError: Error #1007
			logger.error("Activator TypeError, {0}", activator, e2.message);
			// we are going to throw this again so the context.start()
			// method knows we are no in a loading state and not to
			// set the bundle's state to STARTED
			throw e2;
		}
		
		return instance;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Protected :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @abstract
	 */
	protected function loadContext(options:int):void
	{
	}
	
	/**
	 * @abstract
	 */
	protected function startupContext(options:int):void
	{
	}
	
	/**
	 * @private
	 */
	protected function resolve():void
	{
		if (state == BundleState.INSTALLED)
		{
			state = BundleState.RESOLVED;
			dispatchEvent(BundleEvent.BUNDLE_RESOLVED);
		}
	}
	
	/**
	 * @private
	 */
	protected function dispatchEvent(type:String):void
	{
		logger.debug("Bundle '{0}' -> {1}", symbolicName, type);
		bundleService.dispatchEvent(new BundleEvent(type, this));
	}
	
	//--------------------------------------------------------------------------
	//
	//  Public Class :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @private
	 */
	public static function createBundle(bundleData:BundleData, 
										bundleService:IBundleService,
										swiz:ISwiz):IBundle
	{
		var host:BundleProxy = new BundleProxy(bundleData, bundleService, swiz);
		return host;
	}
}
}